<template>
	<view class="page">
		<u-gap height="20"></u-gap>
		<view class="section margin0">
			<view class="title">上传录制的音频</view>
			<view class="tip">为确保最佳训练效果，上传音频保持在5-10秒。</view>
			<!-- 选取音频 -->
			<view class="flex-between margin30">
				<view class="uploadBtn" @click="selectAudioUpload()">选择音频上传</view>
				<view class="uploadBtn" @click="isRecorder = true">录制音频上传</view>
			</view>
		</view>

		<view class="inpVue margin30" v-if="fileUrl && fileName">
			<view class="label">当前上传音频</view>
			<view class="audioVue flex align-center margin20">
				<view class="playBtn relative" @click="uploadAudioPlayFun(fileUrl)">
					<image
						src=""
						style="width: 44rpx; height: 44rpx" class="absolute-auto" v-if="!isUploadPlay"></image>
					<image
						src=""
						style="width: 44rpx; height: 44rpx" class="absolute-auto" v-else></image>
				</view>
				<view class="flex-1 padding-row20 flex-between align-center">
					<text>{{ fileName }}</text>
					<image src="../../static/close.png" style="width: 40rpx; height: 40rpx" @click="
						fileUrl = '';
					fileName = '';
					"></image>
				</view>
			</view>
		</view>

		<!-- 设置声音名称 -->
		<view class="inpVue margin30">
			<view class="label">设置声音名称</view>
			<input type="text" placeholder="请设置声音名称" v-model="name" />
		</view>

		<!-- 性别选择 -->
		<view class="inpVue margin30">
			<view class="label">选择声音性别</view>
			<view class="margin20">
				<u-radio-group v-model="sex" active-color="#F8C329">
					<u-radio v-for="(item, index) in sexes" :key="index" :name="item.name">{{ item.name }}</u-radio>
				</u-radio-group>
			</view>
		</view>

		<!-- 开始训练按钮 -->
		<view class="inpVue margin30">
			<u-checkbox v-model="checked" active-color="#F8C329" label-size="28"><text
					style="color: #81868e; line-height: 1">前两次公开训练，每次最高可获得100积分</text></u-checkbox>
			<view class="startBtn margin20" @click="startFun()">开始训练</view>
			<view class="w100 flex-between align-center margin20">
				<text style="color: #81868e">剩余训练额度：{{ availableQuota }}次</text>
				<text style="color: #f8c329; text-decoration: underline"
					@click="$tools.route('../mine/myVoice')">声音管理</text>
			</view>
		</view>

		<!-- 我的声音列表 -->
		<view class="myList margin50">
			<view class="title" style="padding: 0">我的声音列表</view>
			<view class="margin20">
				<u-subsection :list="tabs" :current="current" button-color="#F8C329" active-color="#fff"
					bg-color="#ececec" @change="change"></u-subsection>
			</view>
			<template v-if="current === 0">
				<view class="item flex align-center margin20" v-for="(item, index) in list" :key="index">
					<view class="playBtn relative" @click="playFun(item.url, item.id)">
						<image
							src=""
							style="width: 44rpx; height: 44rpx" class="absolute-auto" v-if="item.id != audioId">
						</image>
						<image
							src=""
							style="width: 44rpx; height: 44rpx" class="absolute-auto" v-else></image>
					</view>
					<view class="flex-1 flex-between padding-row20 align-center relative">
						<text style="color: #81868e">{{ item.name }}-{{ item.sex }}</text>
						<text v-if="item.status === 2" class="success">成功</text>
						<text v-else-if="item.status === 3" class="success" style="color: #887d75">失败</text>
						<image v-if="item.status === 3"
							src="https://aiet-file-center.oss-cn-hangzhou.aliyuncs.com/shuziren/audio/问号图标1663590.png"
							style="width: 36rpx; height: 36rpx;position: absolute;right: 100rpx"
							@click="showFailureReason(item)">
						</image>
						<u-icon name="trash-fill" size="42" color="#81868e" @click="
							deleteId = item.id;
						show = true;
						" />
					</view>
				</view>
			</template>
			<template v-else>
				<view class="item flex align-center margin20" v-for="(item, index) in list" :key="index">
					<view class="playBtn relative" @click="$u.toast('声音正在训练中')">
						<image
							src=""
							style="width: 44rpx; height: 44rpx" class="absolute-auto"></image>
					</view>
					<view class="progressVue">
						<u-line-progress active-color="#F8C329" inactive-color="#ececec" :percent="item.progress"
							:striped="true" :striped-active="true" height="36"></u-line-progress>
					</view>
				</view>
			</template>
			<view class="w100 flex-column align-center padding-column20" v-if="isEmpty">
				<image src="https://ant-aiet.oss-cn-hangzhou.aliyuncs.com/assets/empty.png"
					style="width: 256rpx; height: 256rpx">
				</image>
				<text style="color: #81868e">{{ describe }}</text>
			</view>
		</view>

		<!-- 删除声音 -->
		<u-modal v-model="show" content="确认删除该声音" confirm-color="#F8C329" :show-cancel-button="true"
			@confirm="deleteSoundTrain"></u-modal>
		<!-- 选择上传音频方式 -->
		<u-popup ref="selectAudioPopup" mode="bottom">
			<view class="select-audio-popup">
				<view class="select-audio-button" @click="skipUploadRecording()">本地文件上传</view>
				<view class="select-audio-button" @click="wxUpload()">微信上传</view>
			</view>
		</u-popup>
		<!-- 录音 -->
		<u-popup v-model="isRecorder" mode="bottom" @close="close">
			<view class="recordVue" v-if="isRecorder">
				<view class="tit">请录制朗读如下文案：</view>
				<view class="text">大家好,我是坏香蕉数字人，坏只是你看到的表象，无论经历多少风雨，我都会笑对人生。</view>
				<view class="tit margin40">训练要求：</view>
				<view class="text">-时长：5到10秒之间</view>
				<view class="text">-语言：普通话</view>
				<view class="text">-音质：咬字清晰明了，无多人声音，不结巴，少语气词</view>
				<view class="text">-文件格式： 音频文件格式</view>
				<view class="text">-上传音频的语速和情感将与最终推理合成想过相似，例如，上传语音语速快，合成时也会快</view>
				<view class="flex-center align-center margin50" style="width: 600rpx">
					<view class="count" v-if="recording">{{ count }}S</view>
					<view class="imgVue">
						<image src="../../static/record1.png" style="width: 250rpx; height: 250rpx" v-if="recording">
						</image>
						<image src="../../static/record.png" style="width: 250rpx; height: 250rpx" v-else></image>
					</view>
					<view class="count" v-if="recording">{{ count }}S</view>
				</view>
				<view class="recordBtn margin50" :class="{ active: recording }" @touchstart="recordTouchstart"
					@touchend="recordTouchend">{{ recording ? "松开结束录音" : "长按开始录音" }}</view>
			</view>
		</u-popup>
		<u-modal v-model="showFailureModal" :content="failureReason" confirm-color="#F8C329" :show-cancel-button="false"
			@confirm="showFailureModal = false"></u-modal>
	</view>
</template>
<script>
import baseUrl from "@/common/url.js";
import chooseFile from "@/common/chooseFile.js";
export default {
	data() {
		return {
			isEmpty: false,
			describe: "暂无",
			showFailureModal: false,
			failureReason: "",
			name: "",
			fileName: "",
			fileUrl: "",
			sex: "男",
			sexes: [
				{
					name: "男",
				},
				{
					name: "女",
				},
			],
			innerAudioContext: null,
			isUploadPlay: false,
			checked: false,
			availableQuota: 0,
			isPlay: false,
			audioId: 0,
			audioContext: null,
			list: [],
			tabs: [
				{
					name: "已完成",
				},
				{
					name: "训练中",
				},
			],
			current: 0,
			record: "", // 全局唯一录音管理区
			isRecorder: false,
			recording: false, // 录音中
			deleteId: "",
			show: false,
			isAuth: null,
			count: 0,
			timer: null,
		};
	},
	async onLoad() {
		this.record = uni.getRecorderManager();
		// this.canRecord();
		this.recordStop();
		await this.getList();
	},
	onShow() {
		this.getSoundQuota();
		// 从缓存里获取文件信息
		const name = uni.getStorageSync("name");
		const url = uni.getStorageSync("url");
		// 校验
		if (name.toString().length > 0 && url.toString().length > 0) {
			// 不为空的情况下填充文件信息
			this.fileName = name;
			this.fileUrl = url;
			// 清除缓存
			uni.removeStorageSync("name");
			uni.removeStorageSync("url");
		}
	},
	methods: {
		async showFailureReason(item) {
			this.failureReason = `训练声音失败: ${item.statusDesc}`;
			this.showFailureModal = true;
		},
		// 获取用户声音训练额度
		async getSoundQuota() {
			const res = await this.$request("/shuziren/soundQuota", {}, "GET");
			if (res.code === 200) this.availableQuota = res.data.availableQuota;
		},

		// 删除声音
		async deleteSoundTrain() {
			const res = await this.$request(
				"/shuziren/soundTrain",
				{
					id: this.deleteId,
				},
				"DELETE"
			);
			if (res.code === 200) {
				this.getList();
				this.$u.toast("删除成功");
			} else {
				this.$u.toast(res.msg);
			}
		},

		change(e) {
			this.current = e;
			this.getList();
		},

		close() {
			this.recording = false;
			this.record.stop();
			this.isRecorder = false;
			this.count = 0;
			clearInterval(this.timer);
			this.timer = null;
		},

		// 开始训练声音
		async startFun() {
			if (this.availableQuota === 0) return this.$u.toast("请购买训练额度");
			if (!this.name) return this.$u.toast("请设置声音名称");
			if (!this.fileUrl) return this.$u.toast("请上传音频");
			uni.showLoading();
			try {
				const res = await this.$request(
					"/shuziren/soundTrain/start",
					{
						name: this.name,
						sex: this.sex,
						isPublic: this.checked,
						url: this.fileUrl,
					},
					"POST",
					"application/json"
				);

				if (res.code === 200) {
					uni.hideLoading();
					this.$u.toast("训练开始，请稍等");
					this.name = "";
					this.fileUrl = "";
					this.availableQuota -= 1;
					this.current = 1;
					this.getList();
				} else {
					uni.hideLoading();
					this.$u.toast(res.msg);
				}
			} catch (error) {
				uni.hideLoading();
				console.error("请求失败:", error);
				this.$u.toast("请求失败，请重试");
			}
		},

		// 获取用户已完成训练的声音列表
		async getList() {
			let url = ["/shuziren/soundTrain/done", "/shuziren/soundTrain/training"][
				this.current
			];
			let data =
				this.current === 0
					? {
						sex: "全部",
					}
					: {};
			const res = await this.$request(url, data, "GET");
			if (res.code === 200) {
				this.list = res.data;
				console.log("获取到声音列表", res);
				this.list.forEach((item) => {
					let statusDesc = "";
					switch (item.status) {
						case 1:
							statusDesc = "进行中";
							break;
						case 2:
							statusDesc = "成功";
							break;
						case 3:
							statusDesc = "失败";
							break;
						default:
							statusDesc = "未知状态";
					}
					item.statusDesc = statusDesc;
					console.log(`声音ID: ${item.id}, 状态: ${statusDesc}`);
				});

				this.isEmpty = this.list.length === 0;
				if (this.current === 0) {
					this.describe = "暂无已完成声音";
				} else {
					this.describe = "暂无训练中声音";
				}
				if (this.current === 1) {
					let pages = getCurrentPages();
					let curRoute = pages[pages.length - 1].route; //获取当前页面路由
					if (curRoute === "pages/index/voice") {
						setTimeout(() => {
							if (this.list.length > 0) this.getList();
						}, 3000);
					}
				}
			}
		},

		// 播放列表音频
		playFun(url, id) {
			if (this.isUploadPlay) {
				this.innerAudioContext.pause();
				this.isUploadPlay = false;
			}
			if (this.audioId && this.audioId != id) {
				this.audioContext.destroy();
				this.audioContext = null;
				this.audioId = 0;
			}
			if (this.audioId && this.audioId == id) {
				this.audioContext.destroy();
				this.audioContext = null;
				this.audioId = 0;
				return;
			}
			this.audioId = id;
			this.audioContext = uni.createInnerAudioContext();
			this.audioContext.autoplay = true;
			this.audioContext.src = url;
			this.audioContext.onPlay(() => {
				console.log("开始播放");
			});
			this.audioContext.onEnded(() => {
				console.log("播放结束");
				this.audioId = 0;
				this.audioContext.destroy();
				this.audioContext = null;
			});
		},

		// 播放上传音频
		uploadAudioPlayFun(url) {
			if (!url) return;
			if (this.audioId) {
				this.audioContext.destroy();
				this.audioContext = null;
				this.audioId = 0;
			}
			if (this.isUploadPlay) {
				this.innerAudioContext.pause();
				this.isUploadPlay = false;
				return;
			}
			this.isUploadPlay = true;
			this.innerAudioContext = uni.createInnerAudioContext();
			this.innerAudioContext.autoplay = true;
			this.innerAudioContext.src = url;
			this.innerAudioContext.onPlay(() => {
				console.log("开始播放");
			});
			this.innerAudioContext.onEnded(() => {
				console.log("播放结束");
				this.isUploadPlay = false;
				this.innerAudioContext.destroy();
				this.innerAudioContext = null;
			});
		},

		// 获取上传音频时长
		recordingDuration(name, url) {
			const that = this;
			that
				.$request(
					"/shuziren/soundTrain/getDuration",
					{
						prompt_wav: url,
					},
					"POST",
					"application/json"
				)
				.then((res) => {
					if (res.code === 200) {
						let durationLimitation = res.data >= 5 && res.data < 10;
						console.log("时长是否在范围内", durationLimitation, res.data);
						if (durationLimitation) {
							that.fileName = name;
							that.fileUrl = url;
							if (that.audioId === 0 && that.isUploadPlay) {
								that.innerAudioContext.destroy();
								that.innerAudioContext = null;
								that.isUploadPlay = false;
							}
						} else {
							that.$u.toast("上传音频保持在5-10秒");
						}
					}
				});
		},

		canRecord() {
			let that = this;
			uni.getSetting({
				success(res) {
					that.isAuth = res.authSetting["scope.record"];
					console.log("录音权限", that.isAuth);
				}
			});
		},

		authFun() {
			let that = this;
			that.canRecord();
			if (that.isAuth) {
				uni.authorize({
					scope: "scope.record",
					success() {
						uni.openSetting();
					},
				});
			}

		},

		recordStop() {
			const that = this;
			that.record.onStop((res) => {
				const tempFilePaths = res.tempFilePath;
				console.log(tempFilePaths);
				uni.uploadFile({
					url: baseUrl.url + "/aiet-file-center/file",
					filePath: tempFilePaths,
					name: "file",
					formData: {
						path: "shuziren/audio",
					},
					success(uploadRes) {
						uni.hideLoading();
						let data = JSON.parse(uploadRes.data);
						console.log(data);
						if (data.code === 200) {
							console.log(new Date().getTime(), data.data.fileUrl);
							that.recordingDuration(new Date().getTime(), data.data.fileUrl);
						} else {
							that.$u.toast(data.msg);
						}
					},
					fail(uploadError) {
						console.log(uploadError);
						that.$u.toast("上传失败");
					},
				});
			});
		},

		// 开始录音 结束录音
		recordTouchstart() {
			if (!this.isAuth) return this.authFun();
			if (this.isAuth == true) console.log("录音权限已开启");
			this.recording = true;
			this.record.start({
				sampleRate: 16000,
				format: "wav",
				duration: 10000,
				encodeBitRate: 96000,
				numberOfChannels: 1,
			});
			this.timer = setInterval(() => {
				this.count++;
				if (this.count >= 10) {
					this.recordTouchend();
				}
			}, 1000);
		},

		recordTouchend() {
			console.log("录音结束");
			this.isRecorder = false;
			this.recording = false;
			this.record.stop();
			this.count = 0;
			clearInterval(this.timer);
			this.timer = null;
		},
		/**
		 * 选择录音文件方式
		 */
		selectAudioUpload() {
			// 打开弹窗
			this.$refs.selectAudioPopup.open();
		},
		/**
		 * 跳转上传音频页面
		 */
		skipUploadRecording() {
			console.log("跳转上传音频页面");
			this.$refs.selectAudioPopup.close();
			uni.navigateTo({
				url: "audio-frequency",
			});
		},
		/**
		 * 从微信获取录音
		 */
		wxUpload() {
			const that = this;
			console.log("从微信获取录音");
			// 关闭弹窗
			that.$refs.selectAudioPopup.close();
			// 打开聊天列表选择音频文件
			wx.chooseMessageFile({
				type: "file",
				count: 1,
				extension: [".wav", ".mp3", ".m4a", ".amr"],
				success(res) {
					const tempFilePaths = res.tempFiles[0];
					console.log(tempFilePaths);
					// 上传选择文件
					uni.uploadFile({
						url: baseUrl.url + "/aiet-file-center/file",
						filePath: tempFilePaths.path,
						name: "file",
						formData: {
							path: "shuziren/audio",
						},
						success(uploadRes) {
							// 加载
							uni.hideLoading();
							let data = JSON.parse(uploadRes.data);
							console.log(data);
							// 校验
							if (data.code === 200) {
								console.log(tempFilePaths.name, data.data.fileUrl);
								// 获取上传音频时长并进行校验
								that.recordingDuration(tempFilePaths.name, data.data.fileUrl);
							} else {
								that.$u.toast(data.msg);
							}
						},
						fail(uploadError) {
							console.log(uploadError);
							that.$u.toast("上传失败");
						},
					});
				},
			});
		},
	},
};
</script>
<style lang="less" scoped>
.section {
	width: 690rpx;
	background: #fff;
	padding: 30rpx;
	box-shadow: 0rpx 0rpx 16rpx 0rpx rgba(178, 178, 178, 0.25),
		inset 0rpx 8rpx 8rpx 0rpx rgba(255, 255, 255, 0.25);
	border-radius: 12rpx;

	.title {
		color: #000;
		font-weight: 600;
		font-size: 30rpx;
		line-height: 1;
	}

	.tip {
		color: #333;
		padding-top: 20rpx;
	}

	.uploadBtn {
		width: 300rpx;
		height: 88rpx;
		border-radius: 12rpx;
		line-height: 88rpx;
		text-align: center;
		color: #fff;
		background: #f8c329;
	}
}

.select-audio-popup {
	height: 256rpx;
}

.select-audio-button {
	height: 100rpx;
	font-size: 30rpx;
	color: #000;
	display: flex;
	justify-content: center;
	align-items: center;
	border-top: 1rpx solid #dddddd;
}

.recordVue {
	width: 100vw;
	padding: 30rpx 30rpx 60rpx;

	.tit {
		color: #000;
		font-weight: 600;
		padding-bottom: 10rpx;
		line-height: 1;
	}

	.text {
		color: #81868e;
	}

	.count {
		width: 80rpx;
		height: 80rpx;
		background: #f8c329;
		text-align: center;
		line-height: 80rpx;
		color: #fff;
		font-weight: 600;
		font-size: 30rpx;
		border-radius: 50%;
	}

	.imgVue {
		width: 250rpx;
		height: 250rpx;
		text-align: center;
		margin: 0 50rpx;
	}

	.recordBtn {
		width: 520rpx;
		height: 88rpx;
		line-height: 88rpx;
		text-align: center;
		background: #f8c329;
		border-radius: 12rpx;
		color: #fff;
	}

	.active {
		background: RGBA(248, 195, 41, 0.5);
	}
}

.inpVue {
	width: 690rpx;
	background: #fff;
	padding: 30rpx;
	box-shadow: 0rpx 0rpx 16rpx 0rpx rgba(178, 178, 178, 0.25),
		inset 0rpx 8rpx 8rpx 0rpx rgba(255, 255, 255, 0.25);
	border-radius: 12rpx;

	.label {
		color: #000;
		font-weight: 600;
		font-size: 30rpx;
	}

	.audioVue {
		width: 100%;
		height: 80rpx;
		border: 1rpx solid #ebeded;
		border-radius: 12rpx;

		.playBtn {
			width: 80rpx;
			height: 80rpx;
			background: #ebeded;
			border-radius: 12rpx 0 0 12rpx;
		}
	}

	input {
		width: 100%;
		height: 88rpx;
		border: 1rpx solid #ebeded;
		border-radius: 12rpx;
		margin-top: 12rpx;
		padding-left: 20rpx;
		font-size: 28rpx;
		box-sizing: border-box;
	}

	.startBtn {
		width: 100%;
		height: 88rpx;
		background: #f8c329;
		border-radius: 12rpx;
		line-height: 88rpx;
		text-align: center;
		color: #fff;
	}
}

.myList {
	width: 690rpx;
	padding-bottom: 30rpx;

	.item {
		width: 100%;
		height: 80rpx;
		border: 1rpx solid #ebeded;
		border-radius: 12rpx;

		.playBtn {
			width: 80rpx;
			height: 80rpx;
			background: #ebeded;
			border-radius: 12rpx 0 0 12rpx;
		}

		.progressVue {
			flex: 1;
			padding: 0 30rpx;
		}
	}
}

.success {
	color: #f8c329;
	position: absolute;
	right: 130rpx;
	width: 80rpx;
}
</style>
